package com.gitee.wsl.android.ext.device

import android.content.pm.PackageManager
import android.graphics.Point
import android.graphics.SurfaceTexture
import android.hardware.Camera
import android.hardware.Camera.AutoFocusCallback
import android.hardware.Camera.CameraInfo
import android.os.AsyncTask
import android.view.SurfaceHolder
import com.gitee.wsl.android.ext.ApplicationInit.application
import com.gitee.wsl.ext.K
import com.gitee.wsl.android.ext.screenSize
import timber.log.Timber
import kotlin.math.abs
import java.lang.StringBuilder

object CameraExt {
   
    // ===============
    // = 摄像头快速处理 =
    // ===============
    /**
     * 判断是否支持反转摄像头 ( 是否存在前置摄像头 )
     * @return `true` yes, `false` no
     */
    fun isSupportReverse(): Boolean {
        try {
            // 默认是不支持
            var isSupportReverse = 0
            // 判断是否支持前置, 支持则使用前置
            if (checkCameraFacing(CameraInfo.CAMERA_FACING_FRONT)) {
                isSupportReverse += 1
                // =
                Timber.d( "支持前置摄像头 ( 手机屏幕 )")
            }
            // 判断是否支持后置, 是则使用后置
            if (checkCameraFacing(CameraInfo.CAMERA_FACING_BACK)) {
                isSupportReverse += 1
                // =
                Timber.d( "支持后置摄像头 ( 手机背面 )")
            }
            // 如果都支持才表示支持反转
            return isSupportReverse == 2
        } catch (e: java.lang.Exception) {
            Timber.d( e, "isSupportReverse")
        }
        // 默认不支持反转摄像头
        return false
    }

    /**
     * 检查是否有指定的摄像头
     * @param facing 摄像头标识 id
     * @return `true` yes, `false` no
     */
    fun checkCameraFacing(facing: Int): Boolean {
        try {
            val cameraCount = Camera.getNumberOfCameras()
            val info = CameraInfo()
            for (i in 0 until cameraCount) {
                Camera.getCameraInfo(i, info)
                if (facing == info.facing) {
                    return true
                }
            }
        } catch (e: java.lang.Exception) {
            Timber.d( e, "checkCameraFacing")
        }
        return false
    }

    /**
     * 判断是否使用前置摄像头
     * @param facing 摄像头标识 id
     * @return `true` yes, `false` no
     */
    fun isFrontCamera(facing: Int): Boolean {
        return facing == CameraInfo.CAMERA_FACING_FRONT
    }

    /**
     * 判断是否使用后置摄像头
     * @param facing 摄像头标识 id
     * @return `true` yes, `false` no
     */
    fun isBackCamera(facing: Int): Boolean {
        return facing == CameraInfo.CAMERA_FACING_BACK
    }

    /**
     * 判断使用的摄像头
     * @param isFrontCamera 是否前置摄像头
     * @return 摄像头标识 id
     */
    fun isUseCameraFacing(isFrontCamera: Boolean): Int {
        // 默认使用后置摄像头
        var cameraFacing = CameraInfo.CAMERA_FACING_BACK
        try {
            // 支持的摄像头 ( 前置, 后置 )
            val cameraFacings = booleanArrayOf(false, false)
            // 判断是否支持前置
            cameraFacings[0] = checkCameraFacing(CameraInfo.CAMERA_FACING_FRONT)
            // 判断是否支持后置
            cameraFacings[1] = checkCameraFacing(CameraInfo.CAMERA_FACING_BACK)
            // 进行判断想要使用的是前置, 还是后置
            cameraFacing = if (isFrontCamera && cameraFacings[0]) { // 使用前置, 必须也支持前置
                // 表示使用前置摄像头
                CameraInfo.CAMERA_FACING_FRONT
            } else {
                // 表示使用后置摄像头
                CameraInfo.CAMERA_FACING_BACK
            }
        } catch (e: java.lang.Exception) {
            Timber.d( e, "isUseCameraFacing")
        }
        return cameraFacing
    }

    // =

    // =
    /**
     * 释放摄像头资源
     * @param camera [android.hardware.Camera]
     */
    fun freeCameraResource(camera: Camera?) {
        try {
            if (camera != null) {
                camera.setPreviewCallback(null)
                camera.stopPreview()
                camera.lock()
                camera.release()
            }
        } catch (e: java.lang.Exception) {
            Timber.d( e, "freeCameraResource")
        }
    }

    /**
     * 初始化摄像头
     * @param camera        [android.hardware.Camera]
     * @param isFrontCamera `true` 前置 ( 屏幕面 ), `false` 后置 ( 手机背面 )
     * @return [android.hardware.Camera]
     */
    fun initCamera(
        camera: Camera?,
        isFrontCamera: Boolean
    ): Camera? {
        // 如果之前存在摄像头数据, 则释放资源
        var camera = camera
        camera?.let { freeCameraResource(it) }
        try {
            // 进行判断想要使用的是前置, 还是后置
            camera = if (isFrontCamera && checkCameraFacing(CameraInfo.CAMERA_FACING_FRONT)) {
                // 初始化前置摄像头
                Camera.open(CameraInfo.CAMERA_FACING_FRONT)
            } else {
                // 初始化后置摄像头
                Camera.open(CameraInfo.CAMERA_FACING_BACK)
            }
        } catch (e: java.lang.Exception) {
            Timber.d( e, "initCamera")
            // 释放资源
            freeCameraResource(camera)
        }
        return camera
    }

    /**
     * 打开摄像头
     * @param cameraId [Camera.CameraInfo] CAMERA_FACING_FRONT( 前置 ), CAMERA_FACING_BACK( 后置 )
     * @return [android.hardware.Camera]
     */
    fun open(cameraId: Int): Camera? {
        // 判断支持的摄像头数量
        var cameraId = cameraId
        val numCameras = Camera.getNumberOfCameras()
        if (numCameras == 0) {
            return null
        }
        try {
            // 判断是否指定哪个摄像头
            val explicitRequest = cameraId >= 0
            // 如果没指定, 则进行判断处理
            if (!explicitRequest) { // 默认使用 后置摄像头, 没有后置才用其他 ( 前置 )
                var index = 0
                while (index < numCameras) {
                    val cameraInfo = CameraInfo()
                    Camera.getCameraInfo(index, cameraInfo)
                    if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
                        break
                    }
                    index++
                }
                cameraId = index
            }
            val camera: Camera?
            camera = if (cameraId < numCameras) {
                Camera.open(cameraId)
            } else {
                if (explicitRequest) {
                    null
                } else {
                    // 默认使用后置
                    Camera.open(CameraInfo.CAMERA_FACING_BACK)
                }
            }
            return camera
        } catch (e: java.lang.Exception) {
            Timber.d( e, "open - cameraId: %s", cameraId)
        }
        return null
    }

    /**
     * 打开摄像头 ( 默认后置摄像头 )
     * @return [android.hardware.Camera]
     */
    fun open(): Camera? {
        return open(-1) // Camera.CameraInfo.CAMERA_FACING_BACK
    }
}

/**
 * detail: 摄像头辅助类
 * @author Ttt
 */
class CameraAssist {
    /**
     * 获取摄像头
     * @return [android.hardware.Camera]
     */
    // 摄像头对象
    var camera: Camera? = null
        private set

    /**
     * 是否预览中
     * @return `true` 预览中, `false` 非预览
     */
    // 是否预览中
    var isPreviewing = false
        private set

    // 自动对焦时间间隔
    private var mAutoInterval = 2000L

    // 预览通知
    private var mPreviewNotify: PreviewNotify? = null

    // ============
    // = 内部工具类 =
    // ============
    // 摄像头大小计算
    private var mCameraSize: CameraSize? = null

    // 自动获取焦点辅助类
    private var mAutoFocus: AutoFocus? = null

    constructor() {}

    /**
     * 构造函数
     * @param camera [android.hardware.Camera]
     */
    constructor(camera: Camera) {
        setCamera(camera)
    }

    /**
     * 构造函数
     * @param camera   [android.hardware.Camera]
     * @param interval 自动对焦时间间隔
     */
    constructor(
        camera: Camera,
        interval: Long
    ) {
        mAutoInterval = interval
        setCamera(camera)
    }
    // ==========
    // = 操作方法 =
    // ==========
    /**
     * 打开摄像头程序
     * @param holder [SurfaceHolder]
     * @return [CameraAssist]
     * @throws Exception 设置预览画面, 异常时抛出
     */
    @Synchronized
    @Throws(java.lang.Exception::class)
    fun openDriver(holder: SurfaceHolder?): CameraAssist {
        val theCamera = camera
        // 设置预览 Holder
        theCamera!!.setPreviewDisplay(holder)
        return this
    }

    /**
     * 关闭摄像头程序
     */
    @Synchronized
    fun closeDriver() {
        // 释放摄像头资源
        freeCameraResource()
    }
    // ==========
    // = 预览相关 =
    // ==========
    /**
     * 开始将 Camera 画面预览到手机上
     */
    @Synchronized
    fun startPreview() {
        val theCamera = camera
        if (theCamera != null && !isPreviewing) {
            // 开始预览
            theCamera.startPreview()
            // 表示预览中
            isPreviewing = true
            // 初始化自动获取焦点
            mAutoFocus = AutoFocus(camera, mAutoInterval)
            // 开始预览通知
            if (mPreviewNotify != null) {
                mPreviewNotify!!.startPreviewNotify()
            }
        }
    }

    /**
     * 停止 Camera 画面预览
     */
    @Synchronized
    fun stopPreview() {
        if (mAutoFocus != null) {
            mAutoFocus!!.stop()
            mAutoFocus = null
        }
        if (camera != null && isPreviewing) {
            // 停止预览
            camera!!.stopPreview()
            // 表示非预览中
            isPreviewing = false
            // 停止预览通知
            if (mPreviewNotify != null) {
                mPreviewNotify!!.stopPreviewNotify()
            }
        }
    }

    /**
     * 释放摄像头资源
     */
    private fun freeCameraResource() {
        try {
            if (camera != null) {
                camera!!.setPreviewCallback(null)
                camera!!.stopPreview()
                camera!!.lock()
                camera!!.release()
            }
        } catch (e: java.lang.Exception) {
            Timber.d( e, "freeCameraResource")
        } finally {
            camera = null
        }
    }

    // ============
    // = 摄像头相关 =
    // ============
    // 预览尺寸大小
    private var mPreviewSize: Camera.Size? = null// 获取预览大小

    /**
     * 获取相机分辨率
     * @return [Camera.Size] 相机分辨率
     */
    val cameraResolution: Camera.Size
        get() {
            if (mPreviewSize == null) { // 获取预览大小
                mPreviewSize = mCameraSize?.getPreviewSize()
            }
            return mPreviewSize!!
        }

    /**
     * 获取预览分辨率
     * @return [Camera.Size] 预览分辨率
     */
    val previewSize: Camera.Size?
        get() = if (camera != null && camera!!.parameters != null) {
            camera!!.parameters.previewSize
        } else null

    /**
     * 获取 Camera.Size 计算辅助类
     * @return [CameraSize]
     */
    val CameraSize: CameraSize?
        get() = mCameraSize

    /**
     * 设置摄像头
     * @param camera [android.hardware.Camera]
     * @return [CameraAssist]
     */
    fun setCamera(camera: Camera): CameraAssist {
        this.camera = camera
        // 初始化 Camera 大小
        mCameraSize = CameraSize(camera)
        return this
    }

    /**
     * 设置预览回调
     * @param previewNotify 预览通知接口
     * @return [CameraAssist]
     */
    fun setPreviewNotify(previewNotify: PreviewNotify?): CameraAssist {
        mPreviewNotify = previewNotify
        return this
    }

    /**
     * 设置是否开启自动对焦
     * @param autoFocus 是否自动对焦
     * @return [CameraAssist]
     */
    fun setAutoFocus(autoFocus: Boolean): CameraAssist {
        mAutoFocus?.isAutoFocus = autoFocus
        return this
    }

    /**
     * 设置自动对焦时间间隔
     * @param autoInterval 自动对焦时间间隔
     * @return [CameraAssist]
     */
    fun setAutoInterval(autoInterval: Long): CameraAssist {
        mAutoInterval = autoInterval
        return this
    }

    /**
     * 打开闪光灯
     * @return `true` success, `false` fail
     */
    fun setFlashlightOn(): Boolean {
        return Flashlight.instance!!.setFlashlightOn(camera)
    }

    /**
     * 关闭闪光灯
     * @return `true` success, `false` fail
     */
    fun setFlashlightOff(): Boolean {
        return Flashlight.instance!!.setFlashlightOff(camera)
    }

    /**
     * 是否打开闪光灯
     * @return `true` yes, `false` no
     */
    val isFlashlightOn: Boolean
        get() = Flashlight.instance!!.isFlashlightOn(camera)
    // =======
    // = 接口 =
    // =======
    /**
     * detail: 预览通知接口
     * @author Ttt
     */
    interface PreviewNotify {
        /**
         * 停止预览通知
         */
        fun stopPreviewNotify()

        /**
         * 开始预览通知
         */
        fun startPreviewNotify()
    }

    companion object {

        // =
        /**
         * 是否支持手机闪光灯
         * @return `true` yes, `false` no
         */
        val isFlashlightEnable: Boolean
            get() = Flashlight.isFlashlightEnable
    }
}


/**
 * detail: 手电筒工具类
 * @author Ttt
 * <pre>
 * 在非 Camera 预览页面使用的话, 需要先调用 register(), 不使用的时候 unregister();
</pre> *
 */
class Flashlight  {

    // Camera 对象
    private var mCamera: Camera? = null

    /**
     * 注册摄像头
     * @return `true` success, `false` fail
     */
    fun register(): Boolean {
        mCamera = try {
            Camera.open(0)
        } catch (ignore: Throwable) {
            return false
        }
        return if (mCamera == null) false else try {
            mCamera!!.setPreviewTexture(SurfaceTexture(0))
            mCamera!!.startPreview()
            true
        } catch (e: Exception) {
            Timber.d( e, "register")
            false
        }
    }

    /**
     * 注销摄像头
     * @return `true` success, `false` fail
     */
    fun unregister(): Boolean {
        if (mCamera == null) return false
        try {
            mCamera!!.stopPreview()
            mCamera!!.release()
            return true
        } catch (e: Exception) {
            Timber.d( e, "unregister")
        }
        return false
    }
    // =
    /**
     * 打开闪光灯
     * @return `true` success, `false` fail
     */
    fun setFlashlightOn(): Boolean {
        return setFlashlightOn(mCamera)
    }

    /**
     * 打开闪光灯
     * @param camera [android.graphics.Camera]
     * @return `true` success, `false` fail
     */
    fun setFlashlightOn(camera: Camera?): Boolean {
        if (camera != null) {
            try {
                val parameters = camera.parameters
                if (parameters != null &&
                    Camera.Parameters.FLASH_MODE_TORCH != parameters.flashMode
                ) {
                    try {
                        parameters.flashMode = Camera.Parameters.FLASH_MODE_TORCH
                        camera.parameters = parameters
                        return true
                    } catch (e: Exception) {
                        Timber.d( e, "setFlashlightOn")
                    }
                }
            } catch (e: Exception) {
                Timber.d( e, "setFlashlightOn - getParameters")
            }
        }
        return false
    }
    // =
    /**
     * 关闭闪光灯
     * @return `true` success, `false` fail
     */
    fun setFlashlightOff(): Boolean {
        return setFlashlightOff(mCamera)
    }

    /**
     * 关闭闪光灯
     * @param camera [android.graphics.Camera]
     * @return `true` success, `false` fail
     */
    fun setFlashlightOff(camera: Camera?): Boolean {
        if (camera != null) {
            try {
                val parameters = camera.parameters
                if (parameters != null && Camera.Parameters.FLASH_MODE_TORCH == parameters.flashMode) {
                    try {
                        parameters.flashMode = Camera.Parameters.FLASH_MODE_OFF
                        camera.parameters = parameters
                        return true
                    } catch (e: Exception) {
                        Timber.d( e, "setFlashlightOff")
                    }
                }
            } catch (e: Exception) {
                Timber.d( e, "setFlashlightOff - getParameters")
            }
        }
        return false
    }
    // =
    /**
     * 是否打开闪光灯
     * @return `true` yes, `false` no
     */
    val isFlashlightOn: Boolean
        get() = isFlashlightOn(mCamera)

    /**
     * 是否打开闪光灯
     * @param camera [android.graphics.Camera]
     * @return `true` yes, `false` no
     */
    fun isFlashlightOn(camera: Camera?): Boolean {
        if (camera != null) {
            try {
                val parameters = camera.parameters
                return parameters != null && Camera.Parameters.FLASH_MODE_TORCH == parameters.flashMode
            } catch (e: Exception) {
                Timber.d( e, "isFlashlightOn")
            }
        }
        return false
    }

    companion object {
        // Flashlight 实例
        @Volatile
        private var sInstance: Flashlight? = null

        /**
         * 获取 Flashlight 实例
         * @return [Flashlight]
         */
        val instance: Flashlight?
            get() {
                if (sInstance == null) {
                    synchronized(Flashlight::class.java) {
                        if (sInstance == null) {
                            sInstance = Flashlight()
                        }
                    }
                }
                return sInstance
            }
        // =
        /**
         * 是否支持手机闪光灯
         * @return `true` yes, `false` no
         */
        val isFlashlightEnable: Boolean
            get() {
                return application.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FLASH)
            }
    }
}

/**
 * detail: 摄像头 ( 预览、输出大小 ) 辅助类
 * @author Ttt
 * <pre>
 * 正常只需要摄像头权限
 * 所需权限
 * <uses-permission android:name="android.permission.CAMERA"></uses-permission> 摄像头
 * <uses-permission android:name="android.permission.VIBRATE"></uses-permission> 震动
 * <uses-permission android:name="android.permission.FLASHLIGHT"></uses-permission> 手电筒
</pre> *
 */
class CameraSize(val camera: Camera,val isPrintLog:Boolean = false) {
    // ==========
    // = 构造函数 =
    // ==========
    // =============
    // = 预览大小相关 =
    // =============
    /**
     * 设置预览大小
     * @param previewSize 预览 [Camera.Size]
     * @return [Camera.Parameters]
     */
    fun setPreviewSize(previewSize: Camera.Size?): Camera.Parameters? {
        return setPreviewSize(null, previewSize)
    }

    /**
     * 设置预览大小
     * @param parameters  [Camera.Parameters]
     * @param previewSize 预览 [Camera.Size]
     * @return [Camera.Parameters]
     */
    fun setPreviewSize(
        parameters: Camera.Parameters?,
        previewSize: Camera.Size?
    ): Camera.Parameters? {
        var parameters = parameters
        if ( previewSize != null) {
            try {
                if (parameters == null) {
                    parameters = camera.parameters
                }
                // 设置预览大小
                parameters!!.setPreviewSize(previewSize.width, previewSize.height)
            } catch (e: java.lang.Exception) {
                Timber.d( e, "setPreviewSize")
            }
        }
        return parameters
    }
    // =
    /**
     * 根据手机支持的预览分辨率计算, 设置预览尺寸
     * @return [Camera.Size] 预览分辨率
     */
    val previewSize: Camera.Size?
        get() = getPreviewSize(null, -1.0)

    /**
     * 根据手机支持的预览分辨率计算, 设置预览尺寸
     * @param point [Point] point.x = 宽, point.y = 高
     * @return [Camera.Size]  预览分辨率
     */
    fun getPreviewSize(point: Point?=null): Camera.Size? {
        return getPreviewSize(point, -1.0)
    }

    /**
     * 根据手机支持的预览分辨率计算, 设置预览尺寸
     * @param distortion 偏差比例值
     * @return [Camera.Size] 预览分辨率
     */
    fun getPreviewSizeUseDistortion(distortion: Double): Camera.Size? {
        return getPreviewSize(null, distortion)
    }

    /**
     * 根据手机支持的预览分辨率计算, 设置预览尺寸 ( 无任何操作, 单独把 Camera 显示到 SurfaceView 预览尺寸 )
     * @param point      指定的尺寸 ( 为 null, 则使用屏幕尺寸 )
     * ( 从指定的宽高, 开始往下 ( 超过的不处理 ) 选择最接近尺寸 ) point.x = 宽, point.y = 高
     * @param distortion 偏差比例值
     * @return [Camera.Size] 预览分辨率
     */
    fun getPreviewSize(
        point: Point?,
        distortion: Double
    ): Camera.Size? {
        try {
            // 计算大小并返回
            return calcPreviewSize(point, distortion)
        } catch (e: java.lang.Exception) {
            Timber.d( e, "getPreviewSize")
        }
        return null
    }
    // =============
    // = 拍照大小相关 =
    // =============
    /**
     * 设置拍照图片大小
     * @param pictureSize 拍照图片 [Camera.Size]
     * @return [Camera.Parameters]
     */
    fun setPictureSize(pictureSize: Camera.Size?): Camera.Parameters? {
        return setPictureSize(null, pictureSize)
    }

    /**
     * 设置拍照图片大小
     * @param parameters  [Camera.Parameters]
     * @param pictureSize 拍照图片 [Camera.Size]
     * @return [Camera.Parameters]
     */
    fun setPictureSize(
        parameters: Camera.Parameters?,
        pictureSize: Camera.Size?
    ): Camera.Parameters? {
        var parameters = parameters
        if ( pictureSize != null) {
            try {
                if (parameters == null) {
                    parameters = camera.parameters
                }
                // 设置拍照大小
                parameters!!.setPictureSize(pictureSize.width, pictureSize.height)
                //                // 设置拍照输出格式
//                parameters.setPictureFormat(PixelFormat.JPEG);
//                // 照片质量
//                parameters.set("jpeg-quality", 70);
            } catch (e: java.lang.Exception) {
                Timber.d( e, "setPictureSize")
            }
        }
        return parameters
    }
    // =
    /**
     * 根据手机支持的拍照分辨率计算
     * @return [Camera.Size] 拍照分辨率
     */
    val pictureSize: Camera.Size?
        get() = getPictureSize(false, null, -1.0)

    /**
     * 根据手机支持的拍照分辨率计算
     * @param max 是否使用最大的尺寸
     * @return [Camera.Size] 拍照分辨率
     */
    fun getPictureSize(max: Boolean): Camera.Size? {
        return getPictureSize(max, null, -1.0)
    }

    /**
     * 根据手机支持的拍照分辨率计算
     * @param point 指定的尺寸 ( 为 null, 则使用屏幕尺寸 )
     * ( 从指定的宽高, 开始往下 ( 超过的不处理 ) 选择最接近尺寸 ) point.x = 宽, point.y = 高
     * @return [Camera.Size] 拍照分辨率
     */
    fun getPictureSize(point: Point?): Camera.Size? {
        return getPictureSize(false, point, -1.0)
    }

    /**
     * 根据手机支持的拍照分辨率计算
     * @param distortion 偏差比例值
     * @return [Camera.Size] 拍照分辨率
     */
    fun getPictureSize(distortion: Double): Camera.Size? {
        return getPictureSize(false, null, distortion)
    }

    /**
     * 根据手机支持的拍照分辨率计算
     * @param point      [Point] point.x = 宽, point.y = 高
     * @param distortion 偏差比例值
     * @return [Camera.Size] 拍照分辨率
     */
    fun getPictureSize(
        point: Point?,
        distortion: Double
    ): Camera.Size? {
        return getPictureSize(false, point, distortion)
    }

    /**
     * 根据手机支持的拍照分辨率计算, 设置预览尺寸
     * @param max        是否使用最大的尺寸
     * @param point      指定的尺寸 ( 为 null, 则使用屏幕尺寸 )
     * ( 从指定的宽高, 开始往下 ( 超过的不处理 ) 选择最接近尺寸 ) point.x = 宽, point.y = 高
     * @param distortion 偏差比例值
     * @return [Camera.Size] 拍照分辨率
     */
    fun getPictureSize(
        max: Boolean,
        point: Point?,
        distortion: Double
    ): Camera.Size? {
        if (camera == null) {
            Timber.d( "camera is null")
            return null
        }
        try {
            // 计算大小并返回
            return calcPictureSize(max, point, distortion)
        } catch (e: java.lang.Exception) {
            Timber.d( e, "getPictureSize")
        }
        return null
    }
    // ================
    // = 视频录制大小相关 =
    // ================
    /**
     * 根据手机支持的视频录制分辨率计算
     * @return [Camera.Size] 视频分辨率
     */
    val videoSize: Camera.Size?
        get() = getVideoSize(false, null, -1.0, false)

    /**
     * 根据手机支持的视频录制分辨率计算
     * @param max 是否使用最大的尺寸
     * @return [Camera.Size] 视频分辨率
     */
    fun getVideoSize(max: Boolean): Camera.Size? {
        return getVideoSize(max, null, -1.0, false)
    }

    /**
     * 根据手机支持的视频录制分辨率计算
     * @param point [Point] point.x = 宽, point.y = 高
     * @return [Camera.Size] 视频分辨率
     */
    fun getVideoSize(point: Point?): Camera.Size? {
        return getVideoSize(false, point, -1.0, false)
    }

    /**
     * 根据手机支持的视频录制分辨率计算
     * @param distortion 偏差比例值
     * @return [Camera.Size] 视频分辨率
     */
    fun getVideoSize(distortion: Double): Camera.Size? {
        return getVideoSize(false, null, distortion, false)
    }

    /**
     * 根据手机支持的视频录制分辨率计算
     * @param point      [Point] point.x = 宽, point.y = 高
     * @param distortion 偏差比例值
     * @return [Camera.Size] 视频分辨率
     */
    fun getVideoSize(
        point: Point?,
        distortion: Double
    ): Camera.Size? {
        return getVideoSize(false, point, distortion, false)
    }

    /**
     * 根据手机支持的视频录制分辨率计算, 设置预览尺寸
     * @param max        是否使用最大的尺寸
     * @param point      指定的尺寸 ( 为 null, 则使用屏幕尺寸 )
     * ( 从指定的宽高, 开始往下 ( 超过的不处理 ) 选择最接近尺寸 ) point.x = 宽, point.y = 高
     * @param distortion 偏差比例值
     * @param minAccord  是否存在最小使用最小
     * @return [Camera.Size] 视频分辨率
     */
    fun getVideoSize(
        max: Boolean,
        point: Point?,
        distortion: Double,
        minAccord: Boolean
    ): Camera.Size? {
        if (camera == null) {
            Timber.d( "camera is null")
            return null
        }
        try {
            // 计算大小并返回
            return calcVideoSize(max, point, distortion, minAccord)
        } catch (e: java.lang.Exception) {
            Timber.d( e, "getVideoSize")
        }
        return null
    }
    // ==========
    // = 预览大小 =
    // ==========
    /**
     * 根据对应的尺寸, 计算相应最符合的大小
     * @param point      指定的尺寸 ( 为 null, 则使用屏幕尺寸 )
     * ( 从指定的宽高, 开始往下 ( 超过的不处理 ) 选择最接近尺寸 ) point.x = 宽, point.y = 高
     * @param distortion 偏差比例值
     * @return [Camera.Size] 预览分辨率
     */
    private fun calcPreviewSize(
        point: Point?,
        distortion: Double
    ): Camera.Size {
        // 判断是否为 null
        var point = point
        var distortion = distortion
        if (point == null) {
            point = getScreenWidthHeightToPoint()
        }
        // 如果误差为负数, 则使用默认值
        if (distortion < 0) {
            distortion = MAX_ASPECT_DISTORTION
        }
        // 获取 Camera 参数
        val params = camera!!.parameters
        // 获取手机支持的分辨率集合, 并以宽度为基准降序排序
        val listPreviewSizes = params.supportedPreviewSizes
            ?: // 获取默认预览大小
            return params.previewSize
        // 防止数据为 null

        // 进行排序处理, 并以宽度 * 高度 为基准降序排序
        listPreviewSizes.sortWith(Comparator { lhs: Camera.Size, rhs: Camera.Size ->
            val leftPixels = lhs.height * lhs.width
            val rightPixels = rhs.height * rhs.width
            rightPixels.compareTo(leftPixels)
        })

        // = 打印信息 =
        if (isPrintLog) {
            val builder = StringBuilder()
            builder.append("预览支持尺寸: ").append(K.SYMBOL.NEW_LINE)
            // 打印信息
            for (previewSize in listPreviewSizes) {
                // 例: 1080 x 1920
                builder.append(previewSize.width)
                    .append("x").append(previewSize.height)
                    .append(K.SYMBOL.NEW_LINE)
            }
            // 打印尺寸信息
            Timber.d( builder.toString())
        }

        // 判断是否竖屏 point.x = 宽, point.y = 高
        if (point.y > point.x) {
            val tempY = point.y
            val tempX = point.x
            // 进行转换
            point.x = tempY
            point.y = tempX
        }

        // 计算比例值 宽 / 高
        val screenAspectRatio = point.x.toDouble() / point.y.toDouble()

        // 循环遍历判断
        val iterator = listPreviewSizes.iterator()
        while (iterator.hasNext()) {
            // 获取预览大小
            val previewSize = iterator.next()
            // 获取宽、高
            val realWidth = previewSize.width
            val realHeight = previewSize.height
            // 小于最小尺寸, 则不处理
            if (realWidth * realHeight < MIN_PREVIEW_PIXELS) {
                iterator.remove()
                continue
            }

            // 判断预选的尺寸是否竖屏
            val isCandidatePortrait = realWidth < realHeight
            // 翻转宽、高
            val maybeFlippedWidth = if (isCandidatePortrait) realHeight else realWidth
            val maybeFlippedHeight = if (isCandidatePortrait) realWidth else realHeight

            // 计算比例
            val aspectRatio = maybeFlippedWidth.toDouble() / maybeFlippedHeight.toDouble()
            val calcDistortion = Math.abs(aspectRatio - screenAspectRatio)

            // 如果大于指定的尺寸比例差, 则跳过
            if (calcDistortion > distortion) {
                iterator.remove()
                continue
            }

            // 如果相符, 则直接跳过
            if (maybeFlippedWidth == point.x && maybeFlippedHeight == point.y) {
                return previewSize
            }
        }

        // 如果没有精确匹配, 则使用最大预览大小
        return if (listPreviewSizes.isNotEmpty()) {
            // 获取最大的尺寸
            listPreviewSizes[0]
        } else params.previewSize

        // = 都不匹配, 则用默认分辨率 =
        // 获取默认预览大小
    }

    private fun getScreenWidthHeightToPoint(): Point {
        val size= application.screenSize
      return Point(size.width,size.height)
    }
    // ==========
    // = 拍照大小 =
    // ==========
    /**
     * 根据对应的尺寸, 计算相应最符合的大小
     * @param max        是否使用最大的尺寸
     * @param point      指定的尺寸 ( 为 null, 则使用屏幕尺寸 )
     * ( 从指定的宽高, 开始往下 ( 超过的不处理 ) 选择最接近尺寸 ) point.x = 宽, point.y = 高
     * @param distortion 偏差比例值
     * @return [Camera.Size] 拍照分辨率
     */
    private fun calcPictureSize(
        max: Boolean,
        point: Point?,
        distortion: Double
    ): Camera.Size {
        // 判断是否为 null
        var point = point
        var distortion = distortion
        if (point == null) {
            point = getScreenWidthHeightToPoint()
        }
        // 如果误差为负数, 则使用默认值
        if (distortion < 0) {
            distortion = MAX_ASPECT_DISTORTION
        }
        // 获取 Camera 参数
        val params = camera!!.parameters
        // 获取手机支持的分辨率集合, 并以宽度为基准降序排序
        val listPictureSizes = params.supportedPictureSizes
            ?: // 获取默认拍照大小
            return params.pictureSize
        // 防止数据为 null

        // 进行排序处理, 并以宽度 * 高度 为基准降序排序
        listPictureSizes.sortWith(Comparator { lhs: Camera.Size, rhs: Camera.Size ->
            val leftPixels = lhs.height * lhs.width
            val rightPixels = rhs.height * rhs.width
            rightPixels.compareTo(leftPixels)
        })

        // = 打印信息 =
        if (isPrintLog) {
            val builder = StringBuilder()
            builder.append("拍照支持尺寸: ").append(K.SYMBOL.NEW_LINE)
            // 打印信息
            for (pictureSize in listPictureSizes) {
                // 例: 1080 x 1920
                builder.append(pictureSize.width)
                    .append("x").append(pictureSize.height)
                    .append(K.SYMBOL.NEW_LINE)
            }
            // 打印尺寸信息
            Timber.d( builder.toString())
        }

        // 判断是否拿最大支持的尺寸
        if (max) {
            return if (!listPictureSizes.isEmpty()) {
                // 获取最大的尺寸
                listPictureSizes[0]
            } else {
                // 获取默认拍照大小
                params.pictureSize
            }
        }

        // 判断是否竖屏 point.x = 宽, point.y = 高
        if (point.y > point.x) {
            val tempY = point.y
            val tempX = point.x
            // 进行转换
            point.x = tempY
            point.y = tempX
        }

        // 计算比例值 宽 / 高
        val pictureAspectRatio = point.x.toDouble() / point.y.toDouble()

        // 判断最大符合
        var maxAccordSize: Camera.Size? = null

        // 循环遍历判断
        val iterator = listPictureSizes.iterator()
        while (iterator.hasNext()) {
            // 获取拍照大小
            val pictureSize = iterator.next()
            // 获取宽、高
            val realWidth = pictureSize.width
            val realHeight = pictureSize.height
            // 小于最小尺寸, 则不处理
            if (realWidth * realHeight < MIN_PREVIEW_PIXELS) {
                iterator.remove()
                continue
            }

            // 判断预选的尺寸是否竖屏
            val isCandidatePortrait = realWidth < realHeight
            // 翻转宽、高
            val maybeFlippedWidth = if (isCandidatePortrait) realHeight else realWidth
            val maybeFlippedHeight = if (isCandidatePortrait) realWidth else realHeight

            // 计算比例
            val aspectRatio = maybeFlippedWidth.toDouble() / maybeFlippedHeight.toDouble()
            val calcDistortion = abs(aspectRatio - pictureAspectRatio)

            // 如果大于指定的尺寸比例差, 则跳过
            if (calcDistortion > distortion) {
                iterator.remove()
                continue
            }

            // 如果相符, 则直接跳过
            if (maybeFlippedWidth == point.x && maybeFlippedHeight == point.y) {
                return pictureSize
            }

            // 保存最大相符的尺寸
            if (maxAccordSize == null) {
                maxAccordSize = pictureSize
            }
        }

        // 如果存在最相符的则返回
        if (maxAccordSize != null) {
            return maxAccordSize
        }

        // 如果没有精确匹配, 则使用最大尺寸大小
        return if (listPictureSizes.isNotEmpty()) {
            // 获取最大的尺寸
            listPictureSizes[0]
        } else params.pictureSize

        // = 都不匹配, 则用默认分辨率 =
        // 获取默认拍照大小
    }
    // =============
    // = 视频录制尺寸 =
    // =============
    /**
     * 根据对应的尺寸, 计算相应最符合的大小
     * @param max        是否使用最大的尺寸
     * @param point      指定的尺寸 ( 为 null, 则使用屏幕尺寸 )
     * ( 从指定的宽高, 开始往下 ( 超过的不处理 ) 选择最接近尺寸 ) point.x = 宽, point.y = 高
     * @param distortion 偏差比例值
     * @param minAccord  是否判断存在最小使用最小
     * @return [Camera.Size] 视频分辨率
     */
    private fun calcVideoSize(
        max: Boolean,
        point: Point?,
        distortion: Double,
        minAccord: Boolean
    ): Camera.Size {
        // 判断是否为 null
        var point = point
        var distortion = distortion
        if (point == null) {
            point = getScreenWidthHeightToPoint()
        }
        // 如果误差为负数, 则使用默认值
        if (distortion < 0) {
            distortion = MAX_ASPECT_DISTORTION
        }
        // 获取 Camera 参数
        val params = camera!!.parameters
        // 获取手机支持的分辨率集合, 并以宽度为基准降序排序
        val listVideoSizes = params.supportedVideoSizes
            ?: // 获取默认拍照大小
            return params.preferredPreviewSizeForVideo
        // 防止数据为 null

        // 进行排序处理, 并以宽度 * 高度 为基准降序排序
        listVideoSizes.sortWith(Comparator { lhs: Camera.Size, rhs: Camera.Size ->
            val leftPixels = lhs.height * lhs.width
            val rightPixels = rhs.height * rhs.width
            rightPixels.compareTo(leftPixels)
        })

        // = 打印信息 =
        if (isPrintLog) {
            val builder = StringBuilder()
            builder.append("视频录制支持尺寸: ").append(K.SYMBOL.NEW_LINE)
            // 打印信息
            for (videoSize in listVideoSizes) {
                // 例: 1080 x 1920
                builder.append(videoSize.width)
                    .append("x").append(videoSize.height)
                    .append(K.SYMBOL.NEW_LINE)
            }
            // 打印尺寸信息
            Timber.d( builder.toString())
        }

        // 判断是否拿最大支持的尺寸
        if (max) {
            return if (listVideoSizes.isNotEmpty()) {
                // 获取最大的尺寸
                listVideoSizes[0]
            } else {
                // 获取默认视频大小
                params.preferredPreviewSizeForVideo
            }
        }

        // 判断是否竖屏 point.x = 宽, point.y = 高
        if (point.y > point.x) {
            val tempY = point.y
            val tempX = point.x
            // 进行转换
            point.x = tempY
            point.y = tempX
        }

        // 计算比例值 宽 / 高
        val videoAspectRatio = point.x.toDouble() / point.y.toDouble()

        // 判断最大符合
        var maxAccordSize: Camera.Size? = null
        // 判断最小符合
        var minAccordSize: Camera.Size? = null

        // 循环遍历判断
        val iterator = listVideoSizes.iterator()
        while (iterator.hasNext()) {
            // 获取视频大小
            val videoSize = iterator.next()
            // 获取宽、高
            val realWidth = videoSize.width
            val realHeight = videoSize.height
            // 小于最小尺寸, 则不处理
            if (realWidth * realHeight < MIN_PREVIEW_PIXELS) {
                iterator.remove()
                continue
            }

            // 判断预选的尺寸是否竖屏
            val isCandidatePortrait = realWidth < realHeight
            // 翻转宽、高
            val maybeFlippedWidth = if (isCandidatePortrait) realHeight else realWidth
            val maybeFlippedHeight = if (isCandidatePortrait) realWidth else realHeight

            // 计算比例
            val aspectRatio = maybeFlippedWidth.toDouble() / maybeFlippedHeight.toDouble()
            val calcDistortion = Math.abs(aspectRatio - videoAspectRatio)

            // 如果大于指定的尺寸比例差, 则跳过
            if (calcDistortion > distortion) {
                iterator.remove()
                continue
            }

            // 如果相符, 则直接跳过
            if (maybeFlippedWidth == point.x && maybeFlippedHeight == point.y) {
                return videoSize
            }

            // 保存最大相符的尺寸
            if (maxAccordSize == null) {
                maxAccordSize = videoSize
            }
            // 保存最小符合的
            minAccordSize = videoSize
        }
        if (minAccord && minAccordSize != null) {
            return minAccordSize
        }

        // 如果存在最相符的则返回
        if (maxAccordSize != null) {
            return maxAccordSize
        }

        // 如果没有精确匹配, 则使用最大尺寸大小
        return if (listVideoSizes.isNotEmpty()) {
            // 获取最大的尺寸
            listVideoSizes[0]
        } else params.preferredPreviewSizeForVideo

        // = 都不匹配, 则用默认分辨率 =
        // 获取默认视频大小
    }

    companion object {

        // 默认最大的偏差
        private const val MAX_ASPECT_DISTORTION = 0.15

        // 最小尺寸, 小于该尺寸则不处理
        private const val MIN_PREVIEW_PIXELS = 153600 // 480 * 320;
    }
}

/**
 * detail: 摄像头自动获取焦点辅助类
 * @author Ttt
 * <pre>
 * 对焦模式
 * @see [](https://blog.csdn.net/fulinwsuafcie/article/details/49558001)
</pre> *
 */
class AutoFocus @JvmOverloads constructor(
    // 摄像头对象
    private val mCamera: Camera?,
    // =======
    // = 变量 =
    // =======
    // 自动对焦时间间隔
    private val mInterval: Long = 2000L
) : AutoFocusCallback {

    // 判断摄像头是否使用对焦
    private var mUseAutoFocus = false

    // 判断是否停止对焦
    private var mStopped = false

    // 判断是否对焦中
    private var mFocusing = false

    // 对焦任务
    private var mOutstandingTask: AsyncTask<*, *, *>? = null

    // 判断是否需要自动对焦
    var isAutoFocus = true
    /**
     * 构造函数
     * @param mCamera   [android.hardware.Camera]
     * @param mInterval 自动对焦时间间隔
     */
    // ==========
    // = 构造函数 =
    // ==========
    /**
     * 构造函数
     * @param camera [android.hardware.Camera]
     */
    init {
        // 防止为 null
        mUseAutoFocus = if (mCamera != null) {
            // 获取对象对焦模式
            val currentFocusMode = mCamera.parameters.focusMode
            // 判断是否支持对焦
            FOCUS_MODES!!.contains(currentFocusMode)
        } else {
            // 不支持对焦
            false
        }
        // 开始任务
        start()
    }
    

    /**
     * 对焦回调 [Camera.AutoFocusCallback] 重写方法
     * @param success   是否对焦成功
     * @param theCamera 对焦的 [android.hardware.Camera]
     */
    @Synchronized
    override fun onAutoFocus(
        success: Boolean,
        theCamera: Camera
    ) {
        // 对焦结束, 设置非对焦中
        mFocusing = false
        // 再次自动对焦
        autoFocusAgainLater()
    }
    // ==========
    // = 内部方法 =
    // ==========
    /**
     * 再次自动对焦
     */
    @Synchronized
    private fun autoFocusAgainLater() {
        // 不属于停止, 并且任务等于 null 才处理
        if (!mStopped && mOutstandingTask == null) {
            // 初始化任务
            val newTask: AutoFocusTask = AutoFocusTask()
            try {
                // 默认使用异步任务
                newTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
                mOutstandingTask = newTask
            } catch (e: java.lang.Exception) {
                Timber.d( e, "autoFocusAgainLater")
            }
        }
    }

    /**
     * 开始对焦
     */
    @Synchronized
    fun start() {
        // 如果不使用自动对焦, 则不处理
        if (!isAutoFocus) return
        // 支持对焦才处理
        if (mUseAutoFocus) {
            // 重置任务为 null
            mOutstandingTask = null
            // 不属于停止 并且 非对焦中
            if (!mStopped && !mFocusing) {
                try {
                    // 设置自动对焦回调
                    mCamera!!.autoFocus(this)
                    // 表示对焦中
                    mFocusing = true
                } catch (e: java.lang.Exception) {
                    Timber.d( e, "start")
                    // Try again later to keep cycle going
                    autoFocusAgainLater()
                }
            }
        }
    }

    /**
     * 停止对焦
     */
    @Synchronized
    fun stop() {
        // 表示属于停止
        mStopped = true
        // 判断是否支持对焦
        if (mUseAutoFocus) {
            try {
                // 关闭任务
                cancelOutstandingTask()
                // 取消对焦
                mCamera!!.cancelAutoFocus()
            } catch (e: java.lang.Exception) {
                Timber.d( e, "stop")
            }
        }
    }

    /**
     * 取消对焦任务
     */
    @Synchronized
    private fun cancelOutstandingTask() {
        if (mOutstandingTask != null) {
            if (mOutstandingTask!!.status != AsyncTask.Status.FINISHED) {
                mOutstandingTask!!.cancel(true)
            }
            mOutstandingTask = null
        }
    }

    /**
     * detail: 自动对焦任务
     * @author Ttt
     */
    private inner class AutoFocusTask :
        AsyncTask<Any, Any?, Any?>() {
        protected override fun doInBackground(vararg voids: Any): Any? {
            try {
                // 堵塞时间
                Thread.sleep(mInterval)
            } catch (ignored: java.lang.Exception) {
            }
            // 开启定时
            start()
            return null
        }
    }

    companion object {
        // 设置对焦模式
        var FOCUS_MODES: MutableCollection<String> = mutableListOf()

        init {
            FOCUS_MODES.add(Camera.Parameters.FOCUS_MODE_AUTO) // 自动对焦
            FOCUS_MODES.add(Camera.Parameters.FOCUS_MODE_MACRO) // 微距
        }

        /**
         * 设置对焦模式
         * @param collection 对焦模式集合
         */
        fun setFocusModes(collection: Collection<String>?) {
            if (collection != null) {
                FOCUS_MODES.clear()
                // 保存对焦模式集合
                FOCUS_MODES.addAll(collection)
            }
        }
    }
}